/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#ifndef mitkMessageHIncluded
#define mitkMessageHIncluded

#include <functional>
#include <itkSimpleFastMutexLock.h>
#include <vector>

/**
 * Adds a Message<> variable and methods to add/remove message delegates to/from
 * this variable.
*/
#define mitkNewMessageMacro(msgHandleObject)                                                                           \
private:                                                                                                               \
  ::mitk::Message<> m_##msgHandleObject##Message;                                                                      \
                                                                                                                       \
public:                                                                                                                \
  inline void Add##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate<> &delegate)                        \
  {                                                                                                                    \
    m_##msgHandleObject##Message += delegate;                                                                          \
  }                                                                                                                    \
  inline void Remove##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate<> &delegate)                     \
  {                                                                                                                    \
    m_##msgHandleObject##Message -= delegate;                                                                          \
  }

#define mitkNewMessageWithReturnMacro(msgHandleObject, returnType)                                                     \
private:                                                                                                               \
  ::mitk::Message<returnType> m_##msgHandleObject##Message;                                                            \
                                                                                                                       \
public:                                                                                                                \
  inline void Add##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate<returnType> &delegate)              \
  {                                                                                                                    \
    m_##msgHandleObject##Message += delegate;                                                                          \
  }                                                                                                                    \
  inline void Remove##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate<returnType> &delegate)           \
  {                                                                                                                    \
    m_##msgHandleObject##Message -= delegate;                                                                          \
  }

#define mitkNewMessage1Macro(msgHandleObject, type1)                                                                   \
private:                                                                                                               \
  ::mitk::Message1<type1> m_##msgHandleObject##Message;                                                                \
                                                                                                                       \
public:                                                                                                                \
  void Add##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate1<type1> &delegate)                         \
  {                                                                                                                    \
    m_##msgHandleObject##Message += delegate;                                                                          \
  }                                                                                                                    \
  void Remove##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate1<type1> &delegate)                      \
  {                                                                                                                    \
    m_##msgHandleObject##Message -= delegate;                                                                          \
  }

#define mitkNewMessage2Macro(msgHandleObject, type1, type2)                                                            \
private:                                                                                                               \
  ::mitk::Message2<type1, type2> m_##msgHandleObject##Message;                                                         \
                                                                                                                       \
public:                                                                                                                \
  void Add##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate2<type1, type2> &delegate)                  \
  {                                                                                                                    \
    m_##msgHandleObject##Message += delegate;                                                                          \
  }                                                                                                                    \
  void Remove##msgHandleObject##Listener(const ::mitk::MessageAbstractDelegate2<type1, type2> &delegate)               \
  {                                                                                                                    \
    m_##msgHandleObject##Message -= delegate;                                                                          \
  }

namespace mitk
{
  template <typename A = void>
  class MessageAbstractDelegate
  {
  public:
    virtual ~MessageAbstractDelegate() {}
    virtual A Execute() const = 0;
    virtual bool operator==(const MessageAbstractDelegate *cmd) const = 0;
    virtual MessageAbstractDelegate *Clone() const = 0;
  };

  template <typename T, typename A = void>
  class MessageAbstractDelegate1
  {
  public:
    virtual ~MessageAbstractDelegate1() {}
    virtual A Execute(T t) const = 0;
    virtual bool operator==(const MessageAbstractDelegate1 *cmd) const = 0;
    virtual MessageAbstractDelegate1 *Clone() const = 0;
  };

  template <typename T, typename U, typename A = void>
  class MessageAbstractDelegate2
  {
  public:
    virtual ~MessageAbstractDelegate2() {}
    virtual A Execute(T t, U u) const = 0;
    virtual bool operator==(const MessageAbstractDelegate2 *cmd) const = 0;
    virtual MessageAbstractDelegate2 *Clone() const = 0;
  };

  template <typename T, typename U, typename V, typename A = void>
  class MessageAbstractDelegate3
  {
  public:
    virtual ~MessageAbstractDelegate3() {}
    virtual A Execute(T t, U u, V v) const = 0;
    virtual bool operator==(const MessageAbstractDelegate3 *cmd) const = 0;
    virtual MessageAbstractDelegate3 *Clone() const = 0;
  };

  template <typename T, typename U, typename V, typename W, typename A = void>
  class MessageAbstractDelegate4
  {
  public:
    virtual ~MessageAbstractDelegate4() {}
    virtual A Execute(T t, U u, V v, W w) const = 0;
    virtual bool operator==(const MessageAbstractDelegate4 *cmd) const = 0;
    virtual MessageAbstractDelegate4 *Clone() const = 0;
  };

  /**
   * This class essentially wraps a function pointer with signature
   * A(R::*function)(). A is the return type of your callback function
   * and R the type of the class implementing the function.
   *
   * Use this class to add a callback function to
   * messages without parameters.
   */
  template <class R, typename A = void>
  class MessageDelegate : public MessageAbstractDelegate<A>
  {
  public:
    // constructor - takes pointer to an object and pointer to a member and stores
    // them in two private variables
    MessageDelegate(R *object, A (R::*memberFunctionPointer)())
      : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer)
    {
    }

    ~MessageDelegate() override {}
    // override function "Call"
    A Execute() const override
    {
      return (m_Object->*m_MemberFunctionPointer)(); // execute member function
    }

    bool operator==(const MessageAbstractDelegate<A> *c) const override
    {
      const MessageDelegate<R, A> *cmd = dynamic_cast<const MessageDelegate<R, A> *>(c);
      if (!cmd)
        return false;

      if ((void *)this->m_Object != (void *)cmd->m_Object)
        return false;
      if (this->m_MemberFunctionPointer != cmd->m_MemberFunctionPointer)
        return false;
      return true;
    }

    MessageAbstractDelegate<A> *Clone() const override { return new MessageDelegate(m_Object, m_MemberFunctionPointer); }
  private:
    R *m_Object;                       // pointer to object
    A (R::*m_MemberFunctionPointer)(); // pointer to member function
  };

  /**
   * This class essentially wraps a function pointer with signature
   * A(R::*function)(T). A is the return type of your callback function,
   * R the type of the class implementing the function and T the type
   * of the argument.
   *
   * Use this class to add a callback function to
   * messages with one parameter.
   *
   * If you need more parameters, use MessageDelegate2 etc.
   */
  template <class R, typename T, typename A = void>
  class MessageDelegate1 : public MessageAbstractDelegate1<T, A>
  {
  public:
    // constructor - takes pointer to an object and pointer to a member and stores
    // them in two private variables
    MessageDelegate1(R *object, A (R::*memberFunctionPointer)(T))
      : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer)
    {
    }

    ~MessageDelegate1() override {}
    // override function "Call"
    A Execute(T t) const override
    {
      return (m_Object->*m_MemberFunctionPointer)(t); // execute member function
    }

    bool operator==(const MessageAbstractDelegate1<T, A> *c) const override
    {
      const MessageDelegate1<R, T, A> *cmd = dynamic_cast<const MessageDelegate1<R, T, A> *>(c);
      if (!cmd)
        return false;

      if ((void *)this->m_Object != (void *)cmd->m_Object)
        return false;
      if (this->m_MemberFunctionPointer != cmd->m_MemberFunctionPointer)
        return false;
      return true;
    }

    MessageAbstractDelegate1<T, A> *Clone() const override { return new MessageDelegate1(m_Object, m_MemberFunctionPointer); }
  private:
    R *m_Object;                        // pointer to object
    A (R::*m_MemberFunctionPointer)(T); // pointer to member function
  };

  template <class R, typename T, typename U, typename A = void>
  class MessageDelegate2 : public MessageAbstractDelegate2<T, U, A>
  {
  public:
    // constructor - takes pointer to an object and pointer to a member and stores
    // them in two private variables
    MessageDelegate2(R *object, A (R::*memberFunctionPointer)(T, U))
      : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer)
    {
    }

    ~MessageDelegate2() override {}
    // override function "Call"
    A Execute(T t, U u) const override
    {
      return (m_Object->*m_MemberFunctionPointer)(t, u); // execute member function
    }

    bool operator==(const MessageAbstractDelegate2<T, U, A> *c) const override
    {
      const MessageDelegate2<R, T, U, A> *cmd = dynamic_cast<const MessageDelegate2<R, T, U, A> *>(c);
      if (!cmd)
        return false;

      if ((void *)this->m_Object != (void *)cmd->m_Object)
        return false;
      if (this->m_MemberFunctionPointer != cmd->m_MemberFunctionPointer)
        return false;
      return true;
    }

    MessageAbstractDelegate2<T, U, A> *Clone() const override { return new MessageDelegate2(m_Object, m_MemberFunctionPointer); }
  private:
    R *m_Object;                           // pointer to object
    A (R::*m_MemberFunctionPointer)(T, U); // pointer to member function
  };

  template <class R, typename T, typename U, typename V, typename A = void>
  class MessageDelegate3 : public MessageAbstractDelegate3<T, U, V, A>
  {
  public:
    // constructor - takes pointer to an object and pointer to a member and stores
    // them in two private variables
    MessageDelegate3(R *object, A (R::*memberFunctionPointer)(T, U, V))
      : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer)
    {
    }

    ~MessageDelegate3() override {}
    // override function "Call"
    A Execute(T t, U u, V v) const override
    {
      return (m_Object->*m_MemberFunctionPointer)(t, u, v); // execute member function
    }

    bool operator==(const MessageAbstractDelegate3<T, U, V, A> *c) const override
    {
      const MessageDelegate3<R, T, U, V, A> *cmd = dynamic_cast<const MessageDelegate3<R, T, U, V, A> *>(c);
      if (!cmd)
        return false;

      if ((void *)this->m_Object != (void *)cmd->m_Object)
        return false;
      if (this->m_MemberFunctionPointer != cmd->m_MemberFunctionPointer)
        return false;
      return true;
    }

    MessageAbstractDelegate3<T, U, V, A> *Clone() const override
    {
      return new MessageDelegate3(m_Object, m_MemberFunctionPointer);
    }

  private:
    R *m_Object;                              // pointer to object
    A (R::*m_MemberFunctionPointer)(T, U, V); // pointer to member function
  };

  template <class R, typename T, typename U, typename V, typename W, typename A = void>
  class MessageDelegate4 : public MessageAbstractDelegate4<T, U, V, W, A>
  {
  public:
    // constructor - takes pointer to an object and pointer to a member and stores
    // them in two private variables
    MessageDelegate4(R *object, A (R::*memberFunctionPointer)(T, U, V, W))
      : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer)
    {
    }

    virtual ~MessageDelegate4() {}
    // override function "Call"
    virtual A Execute(T t, U u, V v, W w) const
    {
      return (m_Object->*m_MemberFunctionPointer)(t, u, v, w); // execute member function
    }

    bool operator==(const MessageAbstractDelegate4<T, U, V, W, A> *c) const
    {
      const MessageDelegate4<R, T, U, V, W, A> *cmd = dynamic_cast<const MessageDelegate4<R, T, U, V, W, A> *>(c);
      if (!cmd)
        return false;

      if ((void *)this->m_Object != (void *)cmd->m_Object)
        return false;
      if (this->m_MemberFunctionPointer != cmd->m_MemberFunctionPointer)
        return false;
      return true;
    }

    MessageAbstractDelegate4<T, U, V, W, A> *Clone() const
    {
      return new MessageDelegate4(m_Object, m_MemberFunctionPointer);
    }

  private:
    R *m_Object;                                 // pointer to object
    A (R::*m_MemberFunctionPointer)(T, U, V, W); // pointer to member function
  };

  template <typename AbstractDelegate>
  class MessageBase
  {
  public:
    typedef std::vector<AbstractDelegate *> ListenerList;

    virtual ~MessageBase()
    {
      for (auto iter = m_Listeners.begin(); iter != m_Listeners.end(); ++iter)
      {
        delete *iter;
      }
    }

    MessageBase() {}
    MessageBase(const MessageBase &o)
    {
      for (typename ListenerList::iterator iter = o.m_Listeners.begin(); iter != o.m_Listeners.end(); ++iter)
      {
        m_Listeners.push_back((*iter)->Clone());
      }
    }

    MessageBase &operator=(const MessageBase &o)
    {
      MessageBase tmp(o);
      std::swap(tmp.m_Listeners, this->m_Listeners);
      return *this;
    }

    void AddListener(const AbstractDelegate &delegate) const
    {
      AbstractDelegate *msgCmd = delegate.Clone();

      m_Mutex.Lock();
      for (auto iter = m_Listeners.begin(); iter != m_Listeners.end(); ++iter)
      {
        if ((*iter)->operator==(msgCmd))
        {
          delete msgCmd;
          m_Mutex.Unlock();
          return;
        }
      }
      m_Listeners.push_back(msgCmd);
      m_Mutex.Unlock();
    }

    void operator+=(const AbstractDelegate &delegate) const { this->AddListener(delegate); }
    void RemoveListener(const AbstractDelegate &delegate) const
    {
      m_Mutex.Lock();
      for (auto iter = m_Listeners.begin(); iter != m_Listeners.end(); ++iter)
      {
        if ((*iter)->operator==(&delegate))
        {
          delete *iter;
          m_Listeners.erase(iter);
          m_Mutex.Unlock();
          return;
        }
      }
      m_Mutex.Unlock();
    }

    void operator-=(const AbstractDelegate &delegate) const { this->RemoveListener(delegate); }
    const ListenerList &GetListeners() const { return m_Listeners; }
    bool HasListeners() const { return !m_Listeners.empty(); }
    bool IsEmpty() const { return m_Listeners.empty(); }
  protected:
    /**
     * \brief List of listeners.
     *
     * This is declared mutable for a reason: Imagine an object that sends out notifications and
     * someone gets a <tt>const Database</tt> object, because he/she should not write to the
     * database. He/she should anyway be able to register for notifications about changes in the database
     * -- this is why AddListener and RemoveListener are declared <tt>const</tt>. m_Listeners must be
     *  mutable so that AddListener and RemoveListener can modify it regardless of the object's constness.
     */
    mutable ListenerList m_Listeners;
    mutable itk::SimpleFastMutexLock m_Mutex;
  };

  /**
   * \brief Event/message/notification class.
   *
   * \sa mitk::BinaryThresholdTool
   * \sa QmitkBinaryThresholdToolGUI
   *
   * This totally ITK, Qt, VTK, whatever toolkit independent class
   * allows one class to send out messages and another class to
   * receive these message. This class is templated over the
   * return type (A) of the callback functions.
   * There are variations of this class
   * (Message1, Message2, etc.) for sending
   * one, two or more parameters along with the messages.
   *
   * This is an implementation of the Observer pattern.
   *
   * \li There is no guarantee about the order of which observer is notified first. At the moment the observers which
   * register first will be notified first.
   * \li Notifications are <b>synchronous</b>, by direct method calls. There is no support for asynchronous messages.
   *
   * To conveniently add methods for registering/unregistering observers
   * to Message variables of your class, you can use the mitkNewMessageMacro
   * macros.
   */
  template <typename A = void>
  class Message : public MessageBase<MessageAbstractDelegate<A>>
  {
  public:
    typedef MessageBase<MessageAbstractDelegate<A>> Super;
    typedef typename Super::ListenerList ListenerList;

    void Send() const
    {
      ListenerList listeners;

      {
        this->m_Mutex.Lock();
        listeners.assign(this->m_Listeners.begin(), this->m_Listeners.end());
        this->m_Mutex.Unlock();
      }

      for (auto iter = listeners.begin(); iter != listeners.end(); ++iter)
      {
        // notify each listener
        (*iter)->Execute();
      }
    }

    void operator()() const { this->Send(); }
  };

  // message with 1 parameter and return type
  template <typename T, typename A = void>
  class Message1 : public MessageBase<MessageAbstractDelegate1<T, A>>
  {
  public:
    typedef MessageBase<MessageAbstractDelegate1<T, A>> Super;
    typedef typename Super::ListenerList ListenerList;

    void Send(T t) const
    {
      ListenerList listeners;

      {
        this->m_Mutex.Lock();
        listeners.assign(this->m_Listeners.begin(), this->m_Listeners.end());
        this->m_Mutex.Unlock();
      }

      for (auto iter = listeners.begin(); iter != listeners.end(); ++iter)
      {
        // notify each listener
        (*iter)->Execute(t);
      }
    }

    void operator() (T t) const { this->Send(t); }
  };

  // message with 2 parameters and return type
  template <typename T, typename U, typename A = void>
  class Message2 : public MessageBase<MessageAbstractDelegate2<T, U, A>>
  {
  public:
    typedef MessageBase<MessageAbstractDelegate2<T, U, A>> Super;
    typedef typename Super::ListenerList ListenerList;

    void Send(T t, U u) const
    {
      ListenerList listeners;

      {
        this->m_Mutex.Lock();
        listeners.assign(this->m_Listeners.begin(), this->m_Listeners.end());
        this->m_Mutex.Unlock();
      }

      for (auto iter = listeners.begin(); iter != listeners.end(); ++iter)
      {
        // notify each listener
        (*iter)->Execute(t, u);
      }
    }

    void operator()(T t, U u) const { this->Send(t, u); }
  };

  // message with 3 parameters and return type
  template <typename T, typename U, typename V, typename A = void>
  class Message3 : public MessageBase<MessageAbstractDelegate3<T, U, V, A>>
  {
  public:
    typedef MessageBase<MessageAbstractDelegate3<T, U, V, A>> Super;
    typedef typename Super::ListenerList ListenerList;

    void Send(T t, U u, V v) const
    {
      ListenerList listeners;

      {
        this->m_Mutex.Lock();
        listeners.assign(this->m_Listeners.begin(), this->m_Listeners.end());
        this->m_Mutex.Unlock();
      }

      for (typename ListenerList::iterator iter = listeners.begin(); iter != listeners.end(); ++iter)
      {
        // notify each listener
        (*iter)->Execute(t, u, v);
      }
    }

    void operator()(T t, U u, V v) const { this->Send(t, u, v); }
  };

  // message with 4 parameters and return type
  template <typename T, typename U, typename V, typename W, typename A = void>
  class Message4 : public MessageBase<MessageAbstractDelegate4<T, U, V, W>>
  {
  public:
    typedef MessageBase<MessageAbstractDelegate4<T, U, V, W, A>> Super;
    typedef typename Super::ListenerList ListenerList;

    void Send(T t, U u, V v, W w) const
    {
      ListenerList listeners;

      {
        this->m_Mutex.Lock();
        listeners.assign(this->m_Listeners.begin(), this->m_Listeners.end());
        this->m_Mutex.Unlock();
      }

      for (typename ListenerList::iterator iter = listeners.begin(); iter != listeners.end(); ++iter)
      {
        // notify each listener
        (*iter)->Execute(t, u, v, w);
      }
    }

    void operator()(T t, U u, V v, W w) const { this->Send(t, u, v, w); }
  };

/* Here is an example how to use the macros and templates:
*
* // An object to be send around
* class Law
* {
*   private:
*     std::string m_Description;
*
*   public:
*
*     Law(const std::string law) : m_Description(law)
*     { }
*
*     std::string GetDescription() const
*     {
*       return m_Description;
*     }
* };
*
* // The NewtonMachine will issue specific events
* class NewtonMachine
* {
*   mitkNewMessageMacro(AnalysisStarted);
*   mitkNewMessage1Macro(AnalysisStopped, bool);
*   mitkNewMessage1Macro(LawDiscovered, const Law&);
*
*   public:
*
*     void StartAnalysis()
*     {
*       // send the "started" signal
*       m_AnalysisStartedMessage();
*
*       // we found a new law of nature by creating one :-)
*       Law massLaw("F=ma");
*       m_LawDiscoveredMessage(massLaw);
*     }
*
*     void StopAnalysis()
*     {
*       // send the "stop" message with false, indicating
*       // that no error occured
*       m_AnalysisStoppedMessage(false);
*     }
* };
*
* class Observer
* {
*   private:
*
*     NewtonMachine* m_Machine;
*
*   public:
*
*     Observer(NewtonMachine* machine) : m_Machine(machine)
*     {
*       // Add "observers", i.e. function pointers to the machine
*       m_Machine->AddAnalysisStartedListener(
*         ::mitk::MessageDelegate<Observer>(this, &Observer::MachineStarted));
*       m_Machine->AddAnalysisStoppedListener(
*         ::mitk::MessageDelegate1<Observer, bool>(this, &Observer::MachineStopped));
*       m_Machine->AddLawDiscoveredListener(
*         ::mitk::MessageDelegate1<Observer, const Law&>(this, &Observer::LawDiscovered));
*      }
*
*     ~Observer()
*     {
*       // Always remove your observers when finished
*       m_Machine->RemoveAnalysisStartedListener(
*         ::mitk::MessagDelegate<Observer>(this, &Observer::MachineStarted));
*       m_Machine->RemoveAnalysisStoppedListener(
*         ::mitk::MessageDelegate1<Observer, bool>(this, &Observer::MachineStopped));
*       m_Machine->RemoveLawDiscoveredListener(
*         ::mitk::MessageDelegate1<Observer, const Law&>(this, &Observer::LawDiscovered));
*      }
*
*      void MachineStarted()
*      {
*        std::cout << "Observed machine has started" << std::endl;
*      }
*
*      void MachineStopped(bool error)
*      {
*        std::cout << "Observed machine stopped " << (error ? "with an error" : "") << std::endl;
*      }
*
*      void LawDiscovered(const Law& law)
*      {
*        std::cout << "New law of nature discovered: " << law.GetDescription() << std::endl;
*      }
*  };
*
*  NewtonMachine newtonMachine;
*  Observer observer(&newtonMachine);
*
*  // This will send two events to registered observers
*  newtonMachine.StartAnalysis();
*  // This will send one event to registered observers
*  newtonMachine.StopAnalysis();
*
* Another example of how to use these message classes can be
* found in the directory Testing, file mitkMessageTest.cpp
*
*/

} // namespace

#endif
